//--------------------------------------------------------------------------------------------------------------
// <copyright file="Service.cs" company="Microsoft Corporation" author="David Martos" date="01/02/2008">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//--------------------------------------------------------------------------------------------------------------

using System;
using System.Data;
using System.Configuration;
using System.ServiceModel;
using System.Web;
using System.Web.Security;

using System.IO;





using System.Web.Services.Protocols;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using CSP.Core;
using Microsoft.Win32;

using CSP.MembershipInterface.ObjectModel;
using System.Reflection;


namespace CSP.CRM.Integration
{

  // A WCF service consists of a contract (defined below as IMyService, DataContract1), 
  // a class which implements that interface (see MyService), 
  // and configuration entries that specify behaviors associated with 
  // that implementation (see <system.serviceModel> in web.config)



  /// <summary>
  /// This class implements the ISimpleCRM interface in order to integrate MOSS with CRM 4.0 in the context
  /// of CSP.
  /// </summary>
  public class MembershipServiceClass : CSP.MembershipInterface.IMembershipServiceContract
  {

    #region Error handling initialization


    public MembershipServiceClass()
    {
      Errors.InitializeLog();
    }

    #endregion

    #region Facade
    /// <summary>
    /// Facade design pattern singleton class
    /// </summary>
    private CrmFacade _facade;
    protected CrmFacade Facade
    {
        get
        {
          string strCrmServerIp = String.Empty, strCrmServerUrl = String.Empty, newCrmServerUrl = String.Empty;
            try
            {
                if (_facade == null)
                {
                    RijndaelCryptography crip = new RijndaelCryptography();
                    crip.Key = RegistryAccess.GetByteArrayProperty(Registry.LocalMachine, CSP.Core.Constants.CspRegistryKey, "CSPCryptographyKey");
                    crip.IV = RegistryAccess.GetByteArrayProperty(Registry.LocalMachine, CSP.Core.Constants.CspRegistryKey, "CSPCryptographyIV");
                    byte[] encryptedPwd = RegistryAccess.GetByteArrayProperty(Registry.LocalMachine, CSP.Core.Constants.CspRegistryKey, "CrmUserPassword");
                    string crmUserPassword = crip.Decrypt(encryptedPwd);


                    strCrmServerUrl = RegistryAccess.GetStringProperty(Registry.LocalMachine, CSP.Core.Constants.CspRegistryKey, "CrmServerUrl");
                    Uri uriCrmServer = new Uri(strCrmServerUrl);
                    string strCrmHostName = uriCrmServer.Host;

                    System.Net.IPHostEntry ipEntries = System.Net.Dns.GetHostEntry(strCrmHostName);
                    strCrmServerIp = ipEntries.AddressList[0].ToString();
                    newCrmServerUrl = String.Format("{0}://{1}", uriCrmServer.Scheme, strCrmServerIp);
                    if (uriCrmServer.Port != 80)
                      newCrmServerUrl += String.Format(":{0}", uriCrmServer.Port);

                    _facade = CrmFacade.CreateCrmFacade(newCrmServerUrl
                        , RegistryAccess.GetStringProperty(Registry.LocalMachine, CSP.Core.Constants.CspRegistryKey, "CrmOrganizationName")
                        , RegistryAccess.GetStringProperty(Registry.LocalMachine, CSP.Core.Constants.CspRegistryKey, "CrmUserName")
                        , crmUserPassword
                        , RegistryAccess.GetStringProperty(Registry.LocalMachine, CSP.Core.Constants.CspRegistryKey, "CrmUserDomain"));

                    System.ServiceModel.Activation.VirtualPathExtension extension = OperationContext.Current.Host.Extensions.Find<System.ServiceModel.Activation.VirtualPathExtension>();
                    string path = System.Web.Hosting.HostingEnvironment.MapPath(extension.VirtualPath + "\\" + "../InfoPathXsl/");
                    _facade.XslDirectory = path;
                }

                return _facade;

            }
            catch (Exception ex)
            {
              throw new ApplicationException(String.Format("Error creating CrmFacade {0} ({1})", strCrmServerUrl, strCrmServerIp), ex);
            }
        }
    
    }
    #endregion


    #region Case
    /// <summary>
    /// Creates a new case (indicent and procedure) into the CRM system using the parameters below.
    /// </summary>
    /// <param name="crmCase">CSP Case entity</param>
    /// <returns>CRM Case GUID</returns>
    public string AddCase(Case crmCase)
    {
      try
      {
        return Facade.CreateProcedure(crmCase.FormXml).ToString();
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }

    }

      public void UpdateCaseSatisfaction(string caseID, int satisfaction)
    {
        try
        {
            Facade.UpdateCaseSatisfaction(caseID, satisfaction);
        }
        catch (CSP.Core.CSPException cspex)
        {
            throw cspex;
        }
        catch (Exception ex)
        {
            throw ex;
        }

    }


    ///// <summary>
    ///// Updates an existing case into the CRM system
    ///// </summary>
    ///// <param name="crmCase">CSP Case entity</param>
    public void UpdateCase(Case crmCase)
    {
      try
      {
        //Facade.u
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Gets the list of existing cases existing into the CRM system
    ///// </summary>
    ///// <returns>CSP Case entity colleciton</returns>
    public Case[] GetCases()
    {
      try
      {
        return Facade.GetCases();
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Gets all the cases mathing the given caseTypeID
    ///// </summary>
    ///// <param name="caseTypeID">Case type ID</param>
    ///// <returns>An array of CSP Case entities</returns>
    public Case[] GetCasesByCaseType(CaseType caseTypeID)
    {
      try
      {
        return Facade.GetCasesByCaseType(caseTypeID);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Gets all the cases mathing the given caseRoleTypeID
    ///// </summary>
    ///// <param name="caseRoleTypeID">Case role type ID</param>
    ///// <returns>An array of CSP Case entities</returns>
    public Case[] GetCasesByCaseRoleType(CaseRoleType caseRoleTypeID)
    {
      try
      {
        return Facade.GetCasesByCaseRoleType(caseRoleTypeID);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Gets all the cases mathing the given caseStatusID
    ///// </summary>
    ///// <param name="caseRoleTypeID">Case status ID</param>
    ///// <returns>An array of CSP Case entities</returns>
    public Case[] GetCasesByCaseStatus(CaseStatus caseStatusID)
    {
      try
      {
        return Facade.GetCasesByCaseStatus(caseStatusID);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Gets all the case information given a caseID
    ///// </summary>
    ///// <param name="caseID">Case ID</param>
    ///// <returns>CSP Case entity</returns>
    public Case GetCaseByCaseID(string caseID)
    {
      try
      {
        return Facade.GetCaseByCaseID(caseID);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Gets all the cases given a citizen username
    ///// </summary>
    ///// <param name="username">Citizen username</param>
    ///// <returns>An array of CSP Case entities</returns>
    public Case[] GetCasesByCitizenID(string username)
    {
      try
      {
        return Facade.GetCasesByCitizenID(username);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }
    #endregion

    #region CaseStatus
    /// <summary>
    /// Not used if not exists Cases Status by Case Type
    /// </summary>
    public DataSet GetCaseStatusesByCaseType(int caseTypeID)
    {
      return null;
    }

    ///// <summary>
    ///// Gets all the cases status
    ///// </summary>
    ///// <returns>An array of CSP CaseStatus entities</returns>
    public CaseStatus[] GetCaseStatus()
    {
      try
      {
        // TODO: tignatov DASB
        // FIX: Used when CSP is installed with CmsConnector.
        // Should not be called when using CrmConnector.
        // Throw Exception instead?
        return new CaseStatus[] {};
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Gets a Case Status with the given Case Status ID
    ///// </summary>
    ///// <param name="caseStatusID">Case Status ID</param>
    ///// <returns>CSP Case Status entity</returns>
    public CaseStatus GetCaseStatusByCaseStatusID(int caseStatusID)
    {
      try
      {

        return null;
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }

    }

    ///// <summary>
    ///// Gets the initial Case Status
    ///// </summary>
    ///// <returns>CSP Case Status entity</returns>
    public CaseStatus GetInitialCaseStatus()
    {
      try
      {
        return null;
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }
    #endregion

    #region CaseRoleType
    public CaseRoleType GetCaseRoleTypeById()
    {
      try
      {
        //Facade.get
        return null;
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    public CaseRoleType[] GetCaseRoleTypes()
    {
      try
      {
        return null;
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    public CaseRoleType GetInitialCaseRoleType()
    {
      try
      {
        return null;
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }
    #endregion

    #region CaseType
    public CaseType GetCaseTypeByName(string name)
    {
      try
      {
        return Facade.GetCaseTypeByName(name);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    /// <summary>
    /// Gets the CaseTypes list stored in the CRM source
    /// </summary>
    /// <returns>CaseType array</returns>
    public CaseType[] GetCaseTypes()
    {
      try
      {
        return Facade.GetCaseTypes();
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }

    }
    #endregion

    #region Citizen

    ///// <summary>
    ///// Gets the list of citizens existing in the CRM system
    ///// </summary>
    ///// <returns>Array of CSP Citizen entities</returns>
    public Citizen[] GetCitizens()
    {
      try
      {
        return Facade.GetCitizens();
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Queries the CRM system to retrieve all the citizen information based on his/her username
    ///// </summary>
    ///// <param name="username">Citizen username</param>
    ///// <returns></returns>
    public Citizen GetCitizenByUsername(string username)
    {
      try
      {
        return Facade.GetCitizenByUsername(username);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }
    #endregion

    #region CitizenRequest
    ///// <summary>
    ///// Gets the list of requests sent by citizens to get access to the CMS
    ///// </summary>
    ///// <returns>Array of CSP CitizenRequest entities</returns>
    public CitizenRequest[] GetCitizenRequests()
    {
      try
      {
        return Facade.GetCitizenRequests();
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Gets a CSP access request sent by the given citizen.
    ///// </summary>
    ///// <param name="username">Citizen username</param>
    ///// <returns>CSP Citizen</returns>
    public CitizenRequest GetCitizenRequestByUsername(string username)
    {
      try
      {
        return Facade.GetCitizenRequestByUserName(username);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Creates a new citizen into the CRM system without enabling him/her to access the online procedures system
    ///// </summary>
    ///// <param name="request">Registration request</param>
    public void AddCitizenRequest(CitizenRequest request)
    {
      try
      {
        Facade.AddCitizenRequest(request);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Allows the CRM citizen with the given username to access the online procedures system
    ///// </summary>
    ///// <param name="username">Citizen username</param>
    public void ApproveCitizenRequest(string username)
    {
      try
      {
        Facade.ApproveCitizenRequest(username);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }

    ///// <summary>
    ///// Deletes the citizen request record stored in CRM system.
    ///// </summary>
    ///// <param name="username">Citizen username</param>
    public void DenyCitizenRequest(string username)
    {
      try
      {
        Facade.DenyCitizenRequest(username);
      }
      catch (CSP.Core.CSPException cspex)
      {
        throw cspex;
      }
      catch (Exception ex)
      {
        throw ex;
      }
    }
    #endregion

  }

}